import { onMounted, onBeforeUnmount, computed, watch } from 'vue';
import type { Options, Column } from './type';
import State from './state';
import { throttle } from "./util"

export default class extends State {
  constructor(options: Options) {
    super(options);

    this._anyWhereSelectedCallbackSelected = this.anyWhereSelectedCallbackSelected.bind(this)

    const keypressUpDownLeftRight = (e) => this.keypressUpDownLeftRight(e)
    const keypressCtrlA = () => this.keypressCtrlA();

    onMounted(() => {
      document.addEventListener('keydown', keypressCtrlA);
      document.addEventListener('keydown', keypressUpDownLeftRight);

      // 还未调试过 以下代码
      // if(typeof this.props.customRow?.().onSelect === 'function'){
      //   this.props.customRow.onSelect?.(this.selectedRangeRowsData.value, this.selectedRangeRowsindex.value)
      // }

    });
    onBeforeUnmount(() => {
      document.removeEventListener('keydown', keypressCtrlA);
      document.removeEventListener('keydown', keypressUpDownLeftRight);
    });

    // 受控的行选择
    if(this.props.customEditer?.selectedRowKeys){
      watch(() => this.props.customEditer?.selectedRowKeys, (keys?: string[]) => {
        this.resetSelectedState();

        const rowindexs = (this.dataSource.value?.map((row: any, rowindex) => {
          const cheosed = keys?.includes?.(row[this.props.rowKey])
          if (cheosed) return rowindex;
          return undefined
        })?.filter(v => v !== undefined)  ?? []) as number[];
        this.selectedState.rows = rowindexs.length ? rowindexs : undefined;

        this.callbackSelected()
      }, {
        immediate: true,
        deep: true
      })
    }
  }

  throttleIntoViewFirstSelected = throttle(this.intoViewFirstSelected, 100)

  selectAreasData = computed(() => {
    return {
      rowindexs: this.getSelectRowindexs(),
      columns: this.getSelectColumns(),
      records: this.getSelectRows(),
      source: this.dataSource,
    }
  });

  /*
  // 内部选择行索引
  selectedRangeRowsindex =  computed(() => {
    let indexs = []
    if(this.selectedState.startY !== undefined){
      let startY = this.getMinStartY()
      const endY = this.getMaxEndY()
      while(startY <= endY){
        indexs.push(startY)
        startY++
      }
    }
    if(this.selectedState.rows){
      indexs = this.selectedState.rows
    }
    return indexs
  })
  // 内部选择行数据
  selectedRangeRowsData = computed(() => {
    if(this.selectedState.startY !== undefined){
      return this.dataSource.value.slice(this.getMinStartY(), this.getMaxEndY() + 1)
    }
    if(this.selectedState.rows){
      return this.selectedState.rows.map((rowindex: number) => this.dataSource.value[rowindex])
    }
    return []
  })
    */

  // 是否选择整行
  isSelectRow(rowindex: number) {
    return (
      this.selectedState.startX === -1 &&
      rowindex >= this.getMinStartY() &&
      rowindex <= this.getMaxEndY()
    ) || this.selectedState.rows?.includes(rowindex);
  }
  // 是否选择表头
  isSelectCol(colindex: number){
    return (
      this.selectedState.selectedTh &&
      colindex >= this.getMinStartX() &&
      colindex <= this.getMaxEndX()
    ) || this.selectedState.cells?.find((item) => {
      return item[0] === -1 && item[1] === colindex;
    });
  }
  // 行中是否有选中单元格
  isSelectedTr(rowindex: number) {
    return (
      this.selectedState.startY !== undefined &&
      rowindex >= this.getMinStartY() &&
      rowindex <= this.getMaxEndY()
    );
  }
  // 是否选中了单元格
  isSelectedTd(rowindex: number, colindex: number) {
    return (
      this.selectedState.startX !== undefined &&
      rowindex >= this.getMinStartY() &&
      rowindex <= this.getMaxEndY() &&
      colindex >= this.getMinStartX() &&
      colindex <= this.getMaxEndX()
    ) || this.selectedState.cells?.find((item) => {
      return item[0] === rowindex && item[1] === colindex;
    });
  }

  isFirstSelectedTh(colindex: number) {
    return (
      this.isSelectCol(colindex) && this.selectedState.startX !== undefined && colindex === this.getMinStartX()
    );
  }
  isLastSelectedTh(colindex: number) {
    return (
      this.isSelectCol(colindex) && this.selectedState.startX !== undefined && colindex === this.getMaxEndX()
    );
  }
  isFirstSelectedTd(colindex: number) {
    return (
      this.selectedState.startX !== undefined && colindex === this.getMinStartX()
    );
  }
  isLastSelectedTd(colindex: number) {
    return (
      this.selectedState.startX !== undefined && colindex === this.getMaxEndX()
    );
  }
  isFirstSelectedTr(rowindex: number) {
    return (
      this.selectedState.startY !== undefined && rowindex === this.getMinStartY()
    );
  }
  isLastSelectedTr(rowindex: number) {
    return (
      this.selectedState.startY !== undefined && rowindex === this.getMaxEndY()
    );
  }

  // 框选单元格
  selectMousedownHandel(rowindex: number, colindex: number) {

    if(this.props.customEditer?.disabledSelectCell) {
      this.selectRowsMousedown(rowindex)
      return;
    }

    if (event.button === 2) return;

    // 按住ctrl、选择其他单元格
    if (event.ctrlKey || event.metaKey) {
      if (this.props.customEditer?.singleSelectCell) return;

      this.transRangeToRows()
      this.anyWhereSelectedCells(rowindex, colindex)
    } else {
      this.selectedState.rows = undefined;
      this.selectedState.cells = undefined;
      this.selectedState.endX = this.selectedState.startX = colindex;
      this.selectedState.endY = this.selectedState.startY = rowindex;
      this.selectedState.selectedTh = false
  
      if (!this.props.customEditer?.singleSelectCell) {
        this.selectMmousemove('td', this.props.customEditer?.singleSelectRow ? this.getCellElement({ rowindex }) : undefined)
      } else {
        this.callbackSelected()
      }
      
    }

    this.listenResetSelectedState()
  }
  // 框选右下角的拖动点
  dragContruneHandel() {
    // 存在自由点选时， 不允许拖动点
    if(this.selectedState.cells || this.selectedState.rows){
      return;
    }

    this.selectMmousemove('td')
    this.listenResetSelectedState()
  }
  // 框选整行
  selectRowsMousedown(rowindex: number) {

    if (this.props.customEditer?.disabledSelectRow) return;

    if (event.button === 2) return;

    // 按住ctrl、选择其他行
    if (event.ctrlKey || event.metaKey) {
      if (this.props.customEditer?.singleSelectRow) return;

      this.anyWhereSelectedRows(rowindex)
    } else {
      this.selectedState.rows = undefined
      this.selectedState.cells = undefined
      this.selectedState.startY = this.selectedState.endY = rowindex;
      this.selectedState.startX = this.selectedState.endX = -1;
      this.selectedState.selectedTh = false
  
      if (event?.target.tagName !== 'TD' && !this.props.customEditer?.disabledSelectCell) return;

      if (!this.props.customEditer?.singleSelectRow) {
        this.selectMmousemove('tr')
      } else {
        this.callbackSelected()
      }
      
    }

    this.listenResetSelectedState()
  }
  // 框选表头
  selectColumnsMousedown(colindex: number) {
    if (this.props.customEditer?.disabledSelectTh) return;

    if (event.button === 2) return;

    if (event.ctrlKey || event.metaKey){
      if (this.props.customEditer?.singleSelectCell) return;

      this.selectedState.selectedTh = false
      this.anyWhereSelectedCells(-1, colindex)
      return;
    } else {
      this.selectedState.rows = undefined
      this.selectedState.cells = undefined
      this.selectedState.selectedTh = true
      this.selectedState.startY = 0
      this.selectedState.endY = this.dataSource.value.length - 1
      this.selectedState.startX = this.selectedState.endX = colindex
      
      if (!this.props.customEditer?.singleSelectCell) {
        if(!this.props.showColDrag){
          this.selectMmousemove('th,td', this.props.customEditer?.singleSelectRow ? this.getCellElement({ rowindex: -1 }) : undefined)
        }
      }
      
    }

    this.listenResetSelectedState()
  }

  // 自由点选单元格
  private anyWhereSelectedCells(rowindex: number, colindex: number) {

    this.transRangeCells()

    const tryfindIndex = this.selectedState.cells?.findIndex(item => item[0] === rowindex && item[1] === colindex) ?? -1;
    if (tryfindIndex > -1) {
      this.selectedState.cells?.splice(tryfindIndex, 1)
      if(this.selectedState.cells?.length === 0) this.selectedState.cells = undefined
    } else {
      this.selectedState.cells?.push([rowindex, colindex])
    }

    document.body.removeEventListener('keyup', this._anyWhereSelectedCallbackSelected)
    document.body.addEventListener('keyup', this._anyWhereSelectedCallbackSelected)
    
  }
  // 范围转换-单元格
  private transRangeCells() {
    if (this.selectedState.cells) return;

    this.selectedState.cells = []
    
    // 此前选中过单元格
    if (this.selectedState.startX !== undefined){
      let startY = this.getMinStartY();
      const endY = this.getMaxEndY();
      let startX = this.getMinStartX();
      const endX = this.getMaxEndX();
      while(startY <= endY){
        startX = this.getMinStartX();
        while(startX <= endX){
          this.selectedState.cells.push([
            startY, startX
          ])
          startX++;
        }
        startY++;
      }

      this.selectedState.endX = this.selectedState.startX = undefined;
      this.selectedState.endY = this.selectedState.startY = undefined;
    }

    // 选中过行
    if (this.selectedState.startX === -1) {
      this.transRangeToRows()
    }
  }
  // 自由点选行
  anyWhereSelectedRows(rowindex: number) {

    this.transRangeToRows()

    const tryfindIndex = this.selectedState.rows?.findIndex(item => item === rowindex) ?? -1;

    if (tryfindIndex > -1) {
      this.selectedState.rows?.splice(tryfindIndex, 1)
      if(this.selectedState.rows?.length === 0) this.selectedState.rows = undefined 
    } else {
      this.selectedState.rows?.push(rowindex)
    }

    document.body.removeEventListener('keyup', this._anyWhereSelectedCallbackSelected)
    document.body.addEventListener('keyup', this._anyWhereSelectedCallbackSelected)

  }
  // 范围转换-行
  private transRangeToRows() {

    if (this.selectedState.rows) return;

    this.selectedState.rows = []

    // 选择了范围
    if(this.selectedState.startX === -1){
      let startY = this.getMinStartY();
      const endY = this.getMaxEndY();
      while(startY <= endY){
        this.selectedState.rows.push(startY)
        startY++;
      }

      this.selectedState.endX = this.selectedState.startX = undefined;
      this.selectedState.endY = this.selectedState.startY = undefined;
    }

    // 选中过单元格
    if (this.selectedState.startX !== undefined) {
      this.transRangeCells()
    }
  }

  // 框选移动事件监听
  private selectMmousemove(target: string, root?: HTMLElement | null) {
    const mousemoveHandel = () => {
      let currentTarget = event?.currentTarget;
      if(target.includes('td') || target.includes('th')) this.selectedState.endX = Number(currentTarget?.getAttribute('data-colindex'));
      if(target.includes('td') || target.includes('tr'))this.selectedState.endY = Number(currentTarget?.getAttribute('data-rowindex'));
    };

    const queryElements: NodeListOf<Element> | undefined = (root || this.table?.value)?.querySelectorAll?.(target)
    queryElements?.forEach((el) => {
      el.addEventListener('mouseenter', mousemoveHandel);
    });

    const remove = () => {
      queryElements?.forEach((el) => {
        el.removeEventListener('mouseenter', mousemoveHandel);
      });
      window.removeEventListener('mouseup', remove);
      this.callbackSelected();
    };
    window.addEventListener('mouseup', remove);
  }

  private keypressUpDownLeftRight(e: any) {
    if (!this.currentView) return;
    if (this.props.customEditer?.disabledSelectRow || this.props.customEditer?.disabledSelectCell) return;
    if (![37, 38, 39, 40, 13, 9].includes(e.keyCode)) return false;

    if (
      !this.selectedState.rows &&
      !this.selectedState.cells &&
      this.selectedState.startY === undefined
    ) {
      this.selectedState.startY = this.selectedState.endY = 0;
      this.selectedState.startX = this.selectedState.endX = -1;
      return false;
    }

    if(this.editState.status === 'doing' && 
      ![undefined, null].includes(this.oldValue) &&
      [37, 39, 9].includes(e.keyCode)
    ){
      return false;
    }

    // 上
    if (e.keyCode === 38) {
      if (this.selectedState.rows) tranRowsToRange('min')
      if (this.selectedState.cells) tranCellsToRange('min')

      this.selectedState.endY = Math.max(this.selectedState.endY - 1, 0);
      this.selectedState.startY = Math.max(this.selectedState.startY - 1, 0);
    }
    // 下 40
    else if (e.keyCode === 40 || e.keyCode === 13) {
      if (this.selectedState.rows) tranRowsToRange('max')
      if (this.selectedState.cells) tranCellsToRange('max')

      this.selectedState.endY = Math.min(this.selectedState.endY + 1, this.dataSource?.value.length - 1);
      this.selectedState.startY = Math.min(this.selectedState.startY + 1, this.dataSource?.value.length - 1);
    }
    // 左 37
    else if (e.keyCode === 37) {
      if (this.selectedState.cells) tranCellsToRange('min')

      this.selectedState.endX = Math.max(this.selectedState.endX - 1, 0);
      this.selectedState.startX = Math.max(this.selectedState.startX - 1, 0);
    }
    // 右 39
    else if (e.keyCode === 39 || e.keyCode === 9) {
      if (this.selectedState.cells) tranCellsToRange('max')

      this.selectedState.endX = Math.min(this.selectedState.endX + 1, this.columns?.value?.length - 1);
      this.selectedState.startX = Math.min(this.selectedState.startX + 1, this.columns?.value?.length - 1);
    }

    // 编辑状态中移动单元格
    if (this.editState.status !== undefined) {
      this.clickEditHandel?.(this.selectedState.startY, this.selectedState.startX)
    }

    const self = this
    function tranCellsToRange(type: 'min' | 'max') {
      if (!self.selectedState.cells) return;
      self.selectedState.startX = self.selectedState.endX = Math[type]?.(...self.selectedState.cells.map(v => v[1])) ?? 0
      self.selectedState.startY = self.selectedState.endY = Math[type]?.(...self.selectedState.cells.map(v => v[0])) ?? 0
      self.selectedState.cells = undefined
    }
    function tranRowsToRange(type: 'min' | 'max') {
      if (!self.selectedState.rows) return;
      self.selectedState.startY = Math[type]?.(...self.selectedState.rows) ?? 0
      self.selectedState.endY = Math[type]?.(...self.selectedState.rows) ?? 0
      self.selectedState.startX = self.selectedState.endX = -1;
      self.selectedState.rows = undefined
    }

    this.callbackSelected();

    e.preventDefault();
    this.throttleIntoViewFirstSelected()
    return false;
  }

  private intoViewFirstSelected(){
    let startX
    let startY
    let node

    if(this.selectedState.cells){
      startX = Math.min(...this.selectedState.cells.map(([rowindex, colindex]) => colindex))
      startY = Math.min(...this.selectedState.cells.map(([rowindex, colindex]) => rowindex))
    }
    else if(this.selectedState.rows){
      startX = Math.min(...this.selectedState.rows)
    }
    else if (this.selectedState.startY !== undefined){
      startX = this.getMinStartX()
      startY = this.getMinStartY()
    }

    if(startY === -1){
      node = this.getCellElement({colindex: startX})
    }else if(startX === -1){
      node = this.getCellElement({rowindex: startY})
    }else if(startY !== undefined){
      node = this.getCellElement({rowindex: startY, colindex: startX})
    }

    node?.scrollIntoView({block: 'center'})
  }

  private checkAllRows() {
    this.selectedState.startX = this.selectedState.endX = -1;
    this.selectedState.startY = 0;
    this.selectedState.endY = this.dataSource.value.length - 1;
    this.callbackSelected()
  }
  private keypressCtrlA() {
    if (!this.currentView) return false;
    if ((event.ctrlKey || event.metaKey) && event.keyCode === 65) {
      event.preventDefault();
      this.checkAllRows();
      return false;
    }
  }

  resetSelectedState(){
    this.selectedState.selectedTh = false
    this.selectedState.endX =
      this.selectedState.startX =
      this.selectedState.endY =
      this.selectedState.startY = 
      this.selectedState.cells = 
      this.selectedState.rows =
        undefined;
  }
  private listenResetSelectedState(){
    
    if(this.props.customEditer?.disabledOuterClickClearSelected) return;

    const documentClickHandel = (e: any) => {
      if (this.showMenus.value) return;
      
      if (e.button === 2) return;

      if (e.ctrlKey || e.metaKey) return;

      let node = e.target;
      while (node && node !== document.body) {
        if (node.tagName === 'TABLE') return false;
        node = node.parentElement;
      }
      this.resetSelectedState()
      document.removeEventListener('click', documentClickHandel);
    };
    document.removeEventListener('click', documentClickHandel);
    document.addEventListener('click', documentClickHandel);
  }

  private getSelectColumns(){
    let columns: Column[] = [];
    if (this.selectedState.rows){
      columns = this.columns.value
    } else if (this.selectedState.cells){
      const colindexs = this.selectedState.cells?.map(v => v[1]) ?? []
      columns =  this.columns.value.filter((v, colindex: number) => {
        return colindexs.includes(colindex);
      })
    } else if (this.selectedState?.startX !== undefined && this.selectedState?.startX >= 0) {
      columns = this.columns.value.filter((v, colindex: number) => {
        return colindex >= this.getMinStartX() && colindex <= this.getMaxEndX();
      })
    }
    return columns
  }
  protected getSelectRowindexs(): number[] {
    let rowindexs = [];
    if (this.selectedState.cells) {
      const indexs: number[] = this.selectedState.cells?.map(v => v[0]) ?? []
      rowindexs = Array.from(new Set(indexs))
    }
    else if (this.selectedState.rows) {
      rowindexs = this.selectedState.rows
    }
    else if (this.selectedState.startY !== undefined) {
      let startY = this.getMinStartY()
      while(startY <= this.getMaxEndY()){
        rowindexs.push(startY)
        startY++
      }
    }
    return rowindexs
  }
  protected getSelectRows(){
    const rowindexs = this.getSelectRowindexs()
    const records = this.dataSource.value.filter((_, rowindex) => rowindexs.includes(rowindex))
    return records;
  }
  protected callbackSelected(){
    if(this.props.openUndo && this.emptyHistoryRecord()) this.addHistoryRecord();
    
    if(typeof this.props.customEditer?.onSelected === 'function'){
      this.props.customEditer?.onSelected(this.selectAreasData.value, this)
    }

    if (this.selectedState.startX === this.selectedState.endX && this.selectedState.startY === this.selectedState.endY){
      this.tryValidateCell?.(this.selectedState.startY, this.selectedState.startX, 'selected');
    }
    
  }
  private anyWhereSelectedCallbackSelected(){
    if (event.ctrlKey || event.metaKey || event.key === 'Control'){
      this.callbackSelected()
    }
  }
}
